//!
/**
 ***********************************************************************************************************
 * <RBEffectPass implementation>
 ***********************************************************************************************************
 * @file RBEffectPass.cpp
 ***********************************************************************************************************/

/************************************************************************************************************
 * Includes
 ************************************************************************************************************/
#include "RBEffectPass.h"

#include "RBMain/RBRenderer.h"
#include "RBMain/RBHardwareBuffer.h"

#include "RBRenderProcess/RBEffectVariable.h"
#include "RBRenderProcess/RBShader.h"
#include "RBRenderProcess/RBShaderResourceView.h"

/************************************************************************************************************/

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
static void SetupShader(EShaderType eST, const RBShader* pShader, RBRenderer* pRenderer, const void* pRawData, 
                        const RBShaderResourceView** ppViews, const RBShaderSamplerState** ppSamplers )
{
    if (!pShader)
    {
        return;
    }

    void* vNativeCB[RBRenderer::ms_uiMaxConstantBuffers];
    char* pStartRawData = (char*)pRawData;
    for (uint32 ui=0; ui < pShader->CommandBuffers.size(); ++ui)
    {
        rb_locked_data mapped_data;
        const RBShaderCommandBuffer& cmdBuffer = pShader->CommandBuffers[ui];
        pRenderer->Map(cmdBuffer.Native, rb_hw_buffer_usage::HBM_WRITE_DISCARD, &mapped_data);

        for (uint32 uiVar = 0; uiVar < cmdBuffer.ConstantBufferVariables.size(); ++uiVar)
        {
            const RBShaderConstantBufferVariable& varCB = cmdBuffer.ConstantBufferVariables[uiVar];
            void* pDstData = (char*)mapped_data.Data + varCB.ConstantBufferOffset;
            const void* pSrcData = pStartRawData+varCB.EffectBufferOffset;
            memcpy(pDstData, pSrcData, varCB.Size);
        }

        pRenderer->Unmap(cmdBuffer.Native);
        vNativeCB[ui] = cmdBuffer.Native;
    }

    void* vNativeRV[RBRenderer::ms_uiMaxShaderResources] = {0};
    for (uint32 ui=0; ui < pShader->ResourceViewVariables.size(); ++ui)
    {
        const RBShaderResourceView* pView = ppViews[pShader->ResourceViewVariables[ui].EffectViewIndex];
        if (pView != NULL && pView->GetNative() != NULL)
        {
            vNativeRV[pShader->ResourceViewVariables[ui].BindPoint] = pView->GetNative();
        }
    }

    void* vNativeSamplers[RBRenderer::ms_uiMaxSamplers] = {0};
    for (uint32 ui=0; ui < pShader->SamplerVariables.size(); ++ui)
    {
        const RBShaderSamplerState* pState = ppSamplers[pShader->SamplerVariables[ui].EffectViewIndex];
        if (pState != NULL && pState->GetNative() != NULL)
        {
            vNativeSamplers[pShader->SamplerVariables[ui].BindPoint] = pState->GetNative();
        }
    }

    // We ignore sampler for now

    switch (eST)
    {
    case EST_VS:
        if (pShader->CommandBuffers.size() > 0)        pRenderer->VSSetConstantBuffers(0, pShader->CommandBuffers.size(), vNativeCB);
        pRenderer->VSSetShaderResources(0, RBRenderer::ms_uiMaxShaderResources, vNativeRV);
        pRenderer->VSSetSamplers       (0, RBRenderer::ms_uiMaxSamplers, vNativeSamplers);
        break;
    case EST_PS:
        if (pShader->CommandBuffers.size() > 0)        pRenderer->PSSetConstantBuffers(0, pShader->CommandBuffers.size(), vNativeCB);
        pRenderer->PSSetShaderResources(0, RBRenderer::ms_uiMaxShaderResources, vNativeRV);
        pRenderer->PSSetSamplers       (0, RBRenderer::ms_uiMaxSamplers, vNativeSamplers);
        break;
    default:
        break;
    }

}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBEffectPass::Begin( RBRenderer* pRenderer, const void* pRawData, const RBShaderResourceView** ppViews, const RBShaderSamplerState** ppSamplers ) const
{
    ::SetupShader(EST_VS, m_aShaders[EST_VS], pRenderer, pRawData, ppViews, ppSamplers);
    ::SetupShader(EST_PS, m_aShaders[EST_PS], pRenderer, pRawData, ppViews, ppSamplers);
    //SetupConstantBuffers(m_pCS, pRenderer, vEffectVariables);
    pRenderer->VSSetShader(m_aShaders[EST_VS]);
    pRenderer->PSSetShader(m_aShaders[EST_PS]);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBEffectPass::End( RBRenderer* /*pRenderer*/ ) const
{

}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBEffectPass::RBEffectPass()
: m_pIASignature(NULL)
, m_uiIASignatureSize(0)
{
    
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBEffectPass::~RBEffectPass()
{
    if (m_pIASignature)
    {
        free(m_pIASignature);
    }
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBEffectPass::CreateIASignature( const void* pIASig, uint32 uiSigSize )
{
    m_pIASignature = malloc(uiSigSize);
    memcpy(m_pIASignature, pIASig, uiSigSize);
    m_uiIASignatureSize = uiSigSize;
}
